package com.zxjbyte.yiyi.framework.common.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.zxjbyte.yiyi.framework.common.exception.ServiceException;
import lombok.experimental.UtilityClass;
import org.springframework.mail.javamail.JavaMailSender;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import java.util.Set;
import java.util.function.Supplier;

/**
 * 校验工具类
 * @Author zhangxingjia
 * @Date 2023/5/12 14:15
 * @Version: 1.0
 */
@UtilityClass
public class ValidationUtil {

    private static class ValidatorHolder {
        private static final Validator INSTANCE =
            SpringUtil.getBean(Validator.class);
    }

    private static Validator getValidator() {
        return ValidatorHolder.INSTANCE;
    }


    public void validate(Object object, Class<?>... groups) {
        Set<ConstraintViolation<Object>> constraintViolations = getValidator().validate(object, groups);
        if (CollXUtil.isNotEmpty(constraintViolations)) {
            throw new ConstraintViolationException(constraintViolations);
        }
    }

    /**
     * Assert that the given object is not null.
     * @param arg
     * @param errorMsg
     * @param params
     */
    public void assertNotNull(Object arg, String errorMsg, Object... params) {
        assertNotNull(arg, () -> StrUtil.format(errorMsg, params));
    }

    public void assertNotNull(Object arg, String argName) {
        assertNotNull(arg, "{} must not be null.", argName);
    }

    public void assertNotNull(Object arg, Supplier<String> errorMsgSupplier) {
        if (arg == null) {
            throw new ServiceException(errorMsgSupplier.get());
        }
    }



    /**
     * Assert that the given string is not empty.
     * @param arg
     * @param errorMsg
     * @param params
     */
    public void assertNotEmpty(String arg, String errorMsg, Object... params) {
        assertNotEmpty(arg, () -> StrUtil.format(errorMsg, params));
    }

    public void assertNotEmpty(String arg, String argName) {
        assertNotEmpty(arg, "{} must be a non-empty string.", argName);
    }

    public void assertNotEmpty(String arg, Supplier<String> errorMsgSupplier) {
        assertNotNull(arg, errorMsgSupplier);
        if (arg.isEmpty()) {
            throw new ServiceException(errorMsgSupplier.get());
        }
    }

    /**
     * Assert that the given string is not blank.
     * @param arg
     * @param errorMsg
     * @param params
     */
    public void assertNotBlank(String arg, String errorMsg, Object... params) {
        assertNotBlank(arg, () -> StrUtil.format(errorMsg, params));
    }

    public void assertNotBlank(String arg, String argName) {
        assertNotBlank(arg, "{} must be a non-empty string.", argName);
    }

    public void assertNotBlank(String arg, Supplier<String> errorMsgSupplier) {
        assertNotNull(arg, errorMsgSupplier);
        if (StrUtil.isBlank(arg)) {
            throw new ServiceException(errorMsgSupplier.get());
        }
    }

    /**
     * Assert that the given number is positive.
     * @param arg
     * @param argName
     */
    public void assertPositive(Number arg, String argName) {
        assertNotNull(arg, argName);
        if (arg.doubleValue() < 0) {
            throw new ServiceException(argName + " cannot be negative.");
        }
    }

    /**
     * 验证集合非空
     * @param collection
     * @param errorMsgTemplate
     * @param params
     * @param <E>
     * @param <T>
     */
    public <E, T extends Iterable<E>> void assertNotEmpty(T collection, String errorMsgTemplate, Object... params) {
        if(CollXUtil.isEmpty(collection)){
            throw new ServiceException(StrUtil.format(errorMsgTemplate, params));
        }
    }

    /**
     * Assert that the given expression is true.
     * @param expression
     * @param errorMsgTemplate
     * @param params
     */
    public void assertTrue(Boolean expression, String errorMsgTemplate, Object... params) {
        assertTrue(expression, () -> new ServiceException(StrUtil.format(errorMsgTemplate, params)));
    }

    public <X extends Throwable> void assertTrue(Boolean expression, Supplier<? extends X> supplier) throws X {
        if (!Boolean.TRUE.equals(expression)) {
            throw supplier.get();
        }
    }

    /**
     * Assert that the given condition is false.
     * @param expression
     * @param errorMsgTemplate
     * @param params
     */
    public void assertFalse(Boolean expression, String errorMsgTemplate, Object... params){
        assertFalse(expression, () -> new ServiceException(StrUtil.format(errorMsgTemplate, params)));
    }

    public <X extends Throwable> void assertFalse(Boolean expression, Supplier<X> errorSupplier) throws X {
        if (Boolean.TRUE.equals(expression)) {
            throw errorSupplier.get();
        }
    }
}
